/*
Copyright 2011, CSE Shareware Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, 
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
   this list of conditions and the following disclaimer in the documentation 
   and/or other materials provided with the distribution.
 * Neither the name of CSE Shareware Foundation nor the names of its contributors 
   may be used to endorse or promote products derived from this software without 
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#if defined(_MSC_VER) || defined(__MINGW32__)
  #include <windows.h>
#endif

#include "CseApi_.h"

// declare local symbol
//==============================================================================
extern TBool gAssertIsReady;
extern TBool gCheckRefCount;
extern TBool gHitBeforeExit;
extern TUint32 gCseObjectRefs[17];

extern CseObj gCseDisableLnDbg;
extern CseObj gExistIDs;

extern FreeObjFunc gFreeObjProc[17];

extern CseObj gCseRegistTable;
extern CseObj gCsePreserves;

extern CseObj gCseTypeStrFunc;
extern CseObj gCseInstFreeFunc;
extern CseObj gCseInstCmpFunc;
extern CseObj gCseInstEqualFunc;
extern CseObj gCseInstStrFunc;
extern CseObj gCseInstBeStrFunc;
extern CseObj gCseInstAsKeyFunc;
extern CseObj gCseInstMapVarFunc;
extern CseObj gCseLogErrorStack;

extern CseObj CseBltinModule;
extern CseObj CseMainModule;

extern CseObj CseEmptySpace;
extern CseObj CseThreadStacks;
extern CseObj CseTraceStack;

extern TXchar *__EmptyString;
extern TInt *__EmptyTier;
extern CseObj *__EmptyBuff;

extern CseObj gScriptEvalFunc;

#ifndef CLOSE_REF_CHECK
  extern TInt32 gGlobalCharArrayCount;
#endif

extern TCriticalSection *CseRecycleLock;

class TRecycleLocker
{
public:
    TRecycleLocker(void)  { CseRecycleLock->enter(); }
    ~TRecycleLocker(void) { CseRecycleLock->leave(); }
};

#define NEW_CSE_BASE_TYPE          Cse_NewBaseType()
#define DEL_CSE_BASE_TYPE(pBase)   Cse_DelBaseType(pBase)

// Following define instance free len str asStr asNum mapVar
//==============================================================================
STATIC TCseException LogCseNotReady(void)
{
    return LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("CSE script system not ready"));
}

TBool GetCseTypeDesc(TCharArray& ret, CseObj value)
{
    TBool (*func)(TCharArray&,CseObj) = (TBool (*)(TCharArray&,CseObj)) gCseTypeStrFunc->vValue;
    if (gAssertIsReady && NULL != func)
        return func(ret,value);
    else return false;
}

void CseInstance_free(CseObj obj)
{
    void (*func)(CseObj) = (void (*)(CseObj)) gCseInstFreeFunc->vValue;
    if (gAssertIsReady && NULL != func) func(obj);
}

TInt CseInstance_cmp(CseObj obj1, CseObj obj2)
{
    if (gAssertIsReady)
    {
        TInt (*func)(CseObj,CseObj) = (TInt (*)(CseObj,CseObj)) gCseInstCmpFunc->vValue;
        if (NULL == func)
            throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("instance comparison invalid"));

        return func(obj1,obj2);
    }
    else return (TInt) (obj1 - obj2);
}

TBool CseInstance_equal(CseObj obj1, CseObj obj2)
{
    if (gAssertIsReady)
    {
        TBool (*func)(CseObj,CseObj) = (TBool (*)(CseObj,CseObj)) gCseInstEqualFunc->vValue;
        if (NULL == func)
            throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("instance comparison invalid"));
            
        return func(obj1,obj2);
    }
    else return obj1 == obj2;
}

CseObj CseInstance_str(CseObj obj)
{
    CseObj (*func)(CseObj) = (CseObj (*)(CseObj)) gCseInstStrFunc->vValue;
    if (gAssertIsReady && NULL != func)
        return func(obj);
    else return CseStr_new(TCharArray::format(_T("<instance:0x%X>"),obj));
}

CseObj CseInstance_BeStr(CseObj obj)
{
    CseObj (*func)(CseObj) = (CseObj (*)(CseObj)) gCseInstBeStrFunc->vValue;
    if (gAssertIsReady && NULL != func)
        return func(obj);
    else return CseStr_new(TCharArray::format(_T("<instance:0x%X>"),obj));
}

CseObj CseInstance_AsKey(CseObj obj)
{
    CseObj (*func)(CseObj) = (CseObj (*)(CseObj)) gCseInstAsKeyFunc->vValue;
    if (gAssertIsReady && NULL != func)
        return func(obj);
    else return Cse_IncRefEx(obj);
}

CseObj CseInstance_MapVar(TXchar flag, va_list& pArg)
{
    CseObj (*func)(TXchar,va_list&) = (CseObj (*)(TXchar,va_list&)) gCseInstMapVarFunc->vValue;
    if (gAssertIsReady && NULL != func)
        return func(flag,pArg);
    else throw LogCseNotReady();
}

// Following define TCseException
//==============================================================================
TCseException::TCseException(const TCseObj& ErrInfo)
{
    if (ErrInfo.type() != dtBuff || ErrInfo.len() == 0)
    {
        ErrorInfo = CseBuff_new(2);
        ErrorInfo->bValue[0] = CseId_new(CSE_UNKNOWN_ERR);
        ErrorInfo->bValue[1] = CseStr_new(CSE_UNDESC_ERROR);
    }
    else ErrorInfo = Cse_IncRefEx(ErrInfo);

    int iLen = Cse_len(ErrorInfo);
    ErrType = (iLen >= 1)? (const TXchar *) ErrorInfo->bValue[0]->sValue: NULL;
    ErrDesc = (iLen >= 2)? (const TXchar *) ErrorInfo->bValue[1]->sValue: NULL;
    ErrFlag = 0;
}

TCseException::TCseException(const TCseException& e)
{
    ErrorInfo = Cse_IncRefEx(e.ErrorInfo);

    int iLen = Cse_len(ErrorInfo);
    ErrType = (iLen >= 1)? (const TXchar *) ErrorInfo->bValue[0]->sValue: NULL;
    ErrDesc = (iLen >= 2)? (const TXchar *) ErrorInfo->bValue[1]->sValue: NULL;
    ErrFlag = 0;
}

TCseException::TCseException(const TCharArray& sErrType, const TCharArray& sErrDesc)
{
    ErrorInfo = CseBuff_new(2);
    ErrorInfo->bValue[0] = CseId_new(sErrType);
    if (sErrDesc.isEmpty())
        ErrorInfo->bValue[1] = CseStr_new(CSE_UNDESC_ERROR);
    else ErrorInfo->bValue[1] = CseStr_new(sErrDesc);

    ErrType = (const TXchar *) ErrorInfo->bValue[0]->sValue;
    ErrDesc = (const TXchar *) ErrorInfo->bValue[1]->sValue;
    ErrFlag = 0;
}

TCseException::TCseException(const TCharArray& sErrType, const TCharArray& sErrDesc, const TCseObj& ErrArg)
{
    ErrorInfo = CseBuff_new(2);
    ErrorInfo->bValue[0] = CseId_new(sErrType);
    ErrorInfo->bValue[1] = CseStr_new(sErrDesc);
    CseBuff_append(ErrorInfo,ErrArg);

    ErrType = (const TXchar *) ErrorInfo->bValue[0]->sValue;
    ErrDesc = (const TXchar *) ErrorInfo->bValue[1]->sValue;
    ErrFlag = 0;
}

TCseException::~TCseException(void)
{
    Cse_DecRef(ErrorInfo);
}

void TCseException::setErrArg(const TCseObj& info) const
{
    int iLen = CSE_ARRAY_LEN(ErrorInfo->bValue);
    if (iLen >= 3)
        CseBuff_set(ErrorInfo,2,info);
    else if (iLen == 2)
        CseBuff_append(ErrorInfo,info);
    else
    {
        CseBuff_StolenAppend(ErrorInfo,CseStr_new(CSE_UNDESC_ERROR));
        CseBuff_append(ErrorInfo,info);
    }
}

TBool TCseException::isError(const TCharArray& ErrType) const
{
    if (CSE_ARRAY_LEN(ErrorInfo->bValue) > 0 && !ErrType.isEmpty())
    {
        TCharArray *s = (TCharArray *) &ErrorInfo->bValue[0]->sValue;
        return s->compare(ErrType) == 0;
    }
    else return false;
}

TCharArray TCseException::getErrType(void) const
{
    TCharArray *s = (TCharArray *) &ErrorInfo->bValue[0]->sValue;
    return *s;
}

TCharArray TCseException::getErrDesc(void) const
{
    if (CSE_ARRAY_LEN(ErrorInfo->bValue) >= 2)
    {
        TCharArray *s = (TCharArray *) &ErrorInfo->bValue[1]->sValue;
        return *s;
    }
    else return CSE_UNDESC_ERROR;
}

TCseObj TCseException::getErrArg(void) const
{
    if (CSE_ARRAY_LEN(ErrorInfo->bValue) >= 3)
        return ErrorInfo->bValue[2];
    else return dummy;
}

TCharArray TCseException::reportStr(void) const
{
    TCharArray *s = (TCharArray *) &ErrorInfo->bValue[0]->sValue;
    TCharArray desc = *s;
    desc += _T(": ");

    if (CSE_ARRAY_LEN(ErrorInfo->bValue) >= 2)
    {
        TCharArray *s2 = (TCharArray *) &ErrorInfo->bValue[1]->sValue;
        desc += *s2;
    }
    else desc += CSE_UNDESC_ERROR;

    return TCharArray(CUT_FROM,desc);
}

TCseObj TCseException::getErrInfo() const
{
    return ErrorInfo;
}

TCseException Cse_LogError(const TCseException& err)
{
    LogErrNameAndDesc(err.getErrType(),err.getErrDesc());

    if (gCseLogErrorStack != NULL && gCseLogErrorStack->vValue != NULL)
    {
        void (*func)(CseObj stack,const TCseException& err) = (void (*)(CseObj,const TCseException&)) gCseLogErrorStack->vValue;
        func(CseTraceStack,err);
    }
    return err;
}

TBool Cse_AssertMsg(int expr, const TXchar *msg)
{
    if (!expr)
    {
        if (gAssertIsReady)
            throw LOG_CSE_ERR(CSE_ASSERT_ERR,msg);
        else throw msg;
    }
    return true;
}

TBool Cse_AssertMsg2(int expr, int iLine, const TXchar *sFile)
{
    if (!expr)
    {
        TCharArray sDesc = TCharArray::format(_T("assert failed at line %d in %s"),iLine,sFile);

        if (gAssertIsReady)
            throw LOG_CSE_ERR(CSE_ASSERT_ERR,sDesc);
        else throw sDesc.addr();
    }
    return true;
}

TCseException Cse_WaitToDo(int line, const TXchar *sFile)
{
    return LOG_CSE_ERR(CSE_NOTIMP_ERR,TCharArray::format(_T("waiting to do at line %d in %s"),line,sFile));
}

// Following define TStolenObj
//==============================================================================
TStolenObj::TStolenObj()
{
    m_obj = dummy;
}

TStolenObj::~TStolenObj()
{
    Cse_DecRef(m_obj);
}

TStolenObj::TStolenObj(CseObj obj)
{
    m_obj = obj;
}

void TStolenObj::bind(CseObj obj)
{
    Cse_DecRef(m_obj);
    m_obj = obj;
}

CseObj TStolenObj::operator->() const
{
    return m_obj;
}

TStolenObj::operator CseObj() const
{
    return m_obj;
}

// Following define common CSE object API
//==============================================================================
#define CSE_RECYCLE_SIZE           512
#define CSE_RECYCLE_MIN            32
#define CSE_RECYCLE_MAX            480     // 512 - 32
#define CSE_RECYCLE_ADJUST         10

CSE_BASE_TYPE *__RecycleBuff[CSE_RECYCLE_SIZE];
TLong __RecycleNum = 0;

CSE_BASE_TYPE* Cse_NewBaseType()
{
    if (__RecycleNum < CSE_RECYCLE_MIN)   // no lock
        return (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    else
    {
        TRecycleLocker lock;
        return __RecycleBuff[--__RecycleNum];
    }
}

void Cse_DelBaseType(CSE_BASE_TYPE *pBase)
{
    if (__RecycleNum > CSE_RECYCLE_MAX)   // no lock
        delete [] pBase;
    else
    {
        TRecycleLocker lock;
        __RecycleBuff[__RecycleNum++] = pBase;
    }
}

void Cse_CleanRecycle()
{
    TRecycleLocker lock;
    while (__RecycleNum > 0)
        delete [] __RecycleBuff[--__RecycleNum];
}

void Cse_IncRef(CseObj obj)
{
    if (obj == dummy || obj == NULL) return;
    TUint32 *pRef = (TUint32 *) ((char *)obj - CSEOBJ_INNER_OFFSET);

    if (0 == *pRef)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("increase zero RefCount"));
    (*pRef)++;
}

void Cse_DecRef(CseObj obj)
{
    if (obj == dummy || obj == NULL) return;
    TUint32 *pRef = (TUint32 *)((char *)obj - CSEOBJ_INNER_OFFSET);

    if (0 == *pRef)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("decrease zero RefCount"));

    (*pRef)--;
    if (0 == *pRef)
    {
        int tp = CSE_TYPE(obj);
        if (tp < dtNotator)
        {
            if (gFreeObjProc[tp](obj))
                gCseObjectRefs[tp]--;
        }
        else
        {
            if (gFreeObjProc[dtNotator](obj))
                gCseObjectRefs[dtNotator]--;
        }
    }
}

CseObj Cse_IncRefEx(CseObj obj)
{
    Cse_IncRef(obj);
    return obj;
}

TUint32 Cse_RefCount(CseObj obj)
{
    return *(TUint32 *)((char *)obj - CSEOBJ_INNER_OFFSET);
}

int Cse_type(CseObj obj)
{
    TInt8 *byteVal = (TInt8 *)((char *)obj - CSEOBJ_TYPE_OFFSET);
    return *byteVal;
}

int Cse_len(CseObj value)
{
    int tp = CSE_TYPE(value);
    if ( dtBuff == tp || tp >= dtNotator || dtStr == tp || dtTier == tp ||
         dtInstance == tp || dtId == tp)
        return CSE_ARRAY_LEN(value->sValue);
    else if (dtDict == tp)
    {
        if (value->entry == NULL)
            return 0;
        else return CSE_ARRAY_LEN(value->sValue);
    }
    else throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("invalid len(obj)"));
}

TBool Cse_FixSize(CseObj value, int iResvd)
{
    int tp = CSE_TYPE(value);

    if (dtDict == tp)
    {
        int iFixedSize = CSE_ARRAY_LEN(value->entry) + iResvd;
        if (value->iFix != 0)
        {
            if (value->iFix < iFixedSize)
                throw LOG_CSE_ERR(CSE_RANGE_ERR,_T("dict size already fixed"));
            value->iFix = iFixedSize;
            return true;
        }
        else
        {
            TEntryArray *pArray = (TEntryArray *) &value->entry;
            pArray->fixSize(iResvd);
            value->iFix = iFixedSize;
            return true;
        }
    }
    else if (dtStr == tp || dtTier == tp || dtBuff == tp)
    {
        if (value->iFix != 0)
            throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("CSE array already fixed"));
        value->iFix = CSE_ARRAY_LEN(value->sValue) + iResvd;
        return true;
    }
    else return false;
}

TUint32 Cse_hash(CseObj obj)
{
    int tp = CSE_TYPE(obj);

    if (tp == dtInt)
        return (TUint32) obj->iValue;
    else if (tp == dtId)
        return (TUint32) obj->hash;
    else if (tp == dtStr)
    {
        TCharArray *s = (TCharArray *) &obj->sValue;
        return s->hash();
    }
    else if (tp == dtFloat || tp == dtWint)
        return (TUint32)(obj->iValue ^ obj->iFlag);
    else return (TUint32)obj;
}

STATIC TInt BaseDataCompare(int tp1, CseObj v1, int tp2, CseObj v2)
{
    if (tp1 == dtInt)
    {
        if (tp2 == dtInt)
            return v1->iValue - v2->iValue;
        else if (tp2 == dtWint)
        {
            if ((TWint)v1->iValue > v2->wValue)
                return 1;
            else if ((TWint)v1->iValue == v2->wValue)
                return 0;
            else return -1;
        }
        else
        {
            ASSERT_TRUE(tp2 == dtFloat);
            if ((TDouble)v1->iValue > v2->fValue)
                return 1;
            else if ((TDouble)v1->iValue == v2->fValue)
                return 0;
            else return -1;
        }
    }
    else if (tp1 == dtWint)
    {
        if (tp2 == dtInt)
        {
            if (v1->wValue > (TWint)v2->iValue)
                return 1;
            else if (v1->wValue == (TWint)v2->iValue)
                return 0;
            else return -1;
        }
        else if (tp2 == dtWint)
        {
            if (v1->wValue > v2->wValue)
                return 1;
            else if (v1->wValue == v2->wValue)
                return 0;
            else return -1;
        }
        else
        {
            ASSERT_TRUE(tp2 == dtFloat);
            if ((TDouble)v1->wValue > v2->fValue)
                return 1;
            else if ((TDouble)v1->wValue == v2->fValue)
                return 0;
            else return -1;
        }
    }
    else
    {
        ASSERT_TRUE(tp1 == dtFloat);
        if (tp2 == dtInt)
        {
            if (v1->fValue > (TDouble)v2->iValue)
                return 1;
            else if (v1->fValue == (TDouble)v2->iValue)
                return 0;
            else return -1;
        }
        else if (tp2 == dtWint)
        {
            if (v1->fValue > (TDouble)v2->wValue)
                return 1;
            else if (v1->fValue == (TDouble)v2->wValue)
                return 0;
            else return -1;
        }
        else
        {
            ASSERT_TRUE(tp2 == dtFloat);
            if (v1->fValue > v2->fValue)
                return 1;
            else if (v1->fValue == v2->fValue)
                return 0;
            else return -1;
        }
    }
}

TInt Cse_ObjComp(CseObj obj1, CseObj obj2, int tp2)
{
    int tp1 = CSE_TYPE(obj1);

    if (tp1 != tp2)
    {
        if (tp1 == dtInstance || tp2 == dtInstance)
            return CseInstance_cmp(obj1,obj2);
        else if (tp1 <= 2 && tp2 <= 2)  // compare between dtInt, dtWint, dtFloat
            return BaseDataCompare(tp1,obj1,tp2,obj2); // 2 == 2.0,  2W = 2.0 ...
        else return tp1 - tp2;
    }
    else  // tp1 == tp2
    {
        if (tp1 == dtStr || tp1 == dtId)
        {
            if (obj1 == obj2) return 0;

            TCharArray *pObj1 = (TCharArray *) &obj1->sValue;
            TCharArray *pObj2 = (TCharArray *) &obj2->sValue;
            return pObj1->compare(*pObj2);
        }
        else if (tp1 == dtInt)
            return (TInt) (obj1->iValue - obj2->iValue);
        else if (tp1 == dtBuff || tp1 >= dtNotator)
        {
            if (obj1 == obj2) return 0;

            TObjArray *pObj1 = (TObjArray *) &obj1->bValue;
            TObjArray *pObj2 = (TObjArray *) &obj2->bValue;
            return pObj1->compare(*pObj2);
        }
        else if (tp1 == dtTier)
        {
            if (obj1 == obj2) return 0;

            TIntArray *pObj1 = (TIntArray *) &obj1->tValue;
            TIntArray *pObj2 = (TIntArray *) &obj2->tValue;
            return pObj1->compare(*pObj2);
        }
        else if (tp1 == dtInstance)
        {
            return CseInstance_cmp(obj1,obj2);
        }
        else if (tp1 == dtFloat)
        {
            if (obj1->fValue == obj2->fValue)
                return 0;
            else if (obj1->fValue > obj2->fValue)
                return 1;
            else return -1;
        }
        else if (tp1 == dtWint)
        {
            if (obj1->wValue == obj2->wValue)
                return 0;
            else if (obj1->wValue > obj2->wValue)
                return 1;
            else return -1;
        }
        else if (tp1 == dtStrong)
            return Cse_ObjComp(obj1->vValue,obj2->vValue,CSE_TYPE(obj2->vValue));
        else if (tp1 == dtWeak)
            return (TInt) (obj1->vValue - obj2->vValue);
        else return (TInt) ((TInt)obj1 - (TInt)obj2);
    }
}

TInt Cse_compare(CseObj self, CseObj other)
{
    return Cse_ObjComp(self,other,CSE_TYPE(other));
}

TBool Cse_equal(CseObj self, CseObj other)
{
    if (self == other)
        return true;
    else
    {
        int tp1 = CSE_TYPE(self);
        int tp2 = CSE_TYPE(other);
        if (tp1 == dtInstance || tp2 == dtInstance)
            return CseInstance_equal(self,other);
        else return 0 == Cse_ObjComp(self,other,tp2);
    }
}

TInt32 Cse_GetFlag(CseObj obj)
{
    return *(TInt32 *)((char *)obj - CSEOBJ_TYPE_OFFSET);
}

void Cse_SetFlag(CseObj obj, TInt32 flag)
{
    // reserve low-8-bits, and set high 24 bits
    flag = flag & 0xFFFFFF00;
    TInt32 *pFlag = (TInt32 *)((TInt8 *)obj - CSEOBJ_TYPE_OFFSET);
    *pFlag = (*pFlag & 0xFF) | flag;
}

TBool Cse_OptionOn(CseObj value, int iOffset)
{
    TInt32 flag = (0x01 << iOffset) & (*(TInt32 *)((char *)value - CSEOBJ_TYPE_OFFSET));
    return flag != 0;
}

void Cse_SetOption(CseObj value, int iOffset)
{
    ASSERT_TRUE(iOffset >= 8);
    TInt32 *pFlag = (TInt32 *)((TInt8 *)value - CSEOBJ_TYPE_OFFSET);
    *pFlag = (*pFlag) | (1 << iOffset);
}

void Cse_ClearOption(CseObj value, int iOffset)
{
    ASSERT_TRUE(iOffset >= 8);
    TInt32 *pFlag = (TInt32 *)((TInt8 *)value - CSEOBJ_TYPE_OFFSET);
    *pFlag = (*pFlag) & ((1 << iOffset) ^ 0xFFFFFFFF);
}

const TXchar *Cse_GetTypeName(int tp)
{
    switch(tp)
    {
        case dtInt:      return _T("int");
        case dtWint:     return _T("wint");
        case dtFloat:    return _T("float");
        case dtStr:      return _T("string");
        case dtTier:     return _T("tier");
        case dtBuff:     return _T("buff");
        case dtDict:     return _T("dict");
        case dtInstance: return _T("instance");
        case dtId:       return _T("ID");
        case dtStrong:   return _T("strong");
        case dtWeak:     return _T("weak");
        case dtNotator:  return _T("notator");
        default:         return _T("unknown");
    }
}

STATIC void Cse_FuncDesc(TCharArray& ret, int tp, CseObj FuncId)
{
    if (tp == CSE_ATOMCALL_FLAG)
    {
        TInt8 flag = (TInt8)FuncId->bFlag.b1;
        switch(flag & 0x0F)
        {
        case dsIterCdecl:   ret = _T("IterCdecl");   break;
        case dsIterStdcall: ret = _T("IterStdcall"); break;
        case dsIterScript:  ret = _T("IterScript");  break;
        case dsFrmtScript:  ret = _T("FrmtScript");  break;
        case dsPostCdecl:   ret = _T("PostCdecl");   break;
        case dsPostStdcall: ret = _T("PostStdcall"); break;
        default: ret = _T("unknown");
        }
    }

    else Cse_str(ret,FuncId);
}

STATIC void Cse_GetRecursiveDesc(CseObj value, TCharArray& ret)
{
    ret = TCharArray::format(_T("<recursive:0x%X>"),value);
}

STATIC TBool GetStrObjValue(TCharArray& ret, CseObj value, TBool beStr=false)
{
    if (CSE_ARRAY_LEN(value->bValue) >= 2 && value->bValue[0] == gCppStrType)
    {
        CseObj v = value->bValue[1];
        int tp = CSE_TYPE(v);
        if (tp == dtInt)
        {
            TCharArray *pCh = (TCharArray *) v->iValue;
            if (pCh == NULL)
                ret = _T("<NULL>");
            else ret = *pCh;
            return true;
        }
        else if (tp == dtStrong)
        {
            if (beStr)
                Cse_BeStr(ret,v->vValue);
            else Cse_str(ret,v->vValue);
            return true;
        }
    }
    return false;
}

void Cse_str(TCharArray& ret, CseObj value)
{
    int tp = CSE_TYPE(value);

    if (tp == dtInstance)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                if (GetStrObjValue(ret,value)) return;

                CseObj v = CseInstance_str(value);
                if (NULL != v)
                {
                    tp = CSE_TYPE(v);
                    if (dtStr == tp || dtId == tp)
                    {
                        TCharArray *s = (TCharArray *) &v->sValue;
                        ret = *s;
                    }
                    else if (dtInstance == tp && GetStrObjValue(ret,v))
                    {
                        Cse_DecRef(v);
                        return;
                    }
                    else ret = TCharArray::format(_T("<instance:0x%X>"),value);
                    Cse_DecRef(v);
                }
                else ret = TCharArray::format(_T("<instance:0x%X>"),value);
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (Cse_OptionOn(value,16))
    {
        if (! GetCseTypeDesc(ret,value))
            ret = TCharArray::format(_T("<type:0x%X>"),value);
    }

    else if (tp >= dtNotator)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                TCharArray sDesc;
                Cse_FuncDesc(sDesc,tp,value->bValue[0]);
                ret = _T('<') + sDesc + _T(":>");
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (tp == dtInt)
        ret = TCharArray::format(_T("%d"),value->iValue);

    else if (tp == dtStr)
    {
        TCharArray *s = (TCharArray *) &value->sValue;
        ret = s->str();
    }
    
    else if (tp == dtId)
    {
        TCharArray *s = (TCharArray *) &value->sValue;
        ret = *s;  // copy transfer
    }

    else if (tp == dtTier)
    {
        TIntArray *t = (TIntArray *) &value->tValue;
        ret = t->str();
    }

    else if (tp == dtBuff)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                TObjArray *b = (TObjArray *) &value->bValue;
                ret = b->str();
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (tp == dtDict)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                TEntryArray *d = (TEntryArray *) &value->entry;
                ret = d->str();
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (tp == dtWint)
        ret = TCharArray::format(_T("%" CseLongLongFmtSpec _T("dW")),value->wValue);

    else if (tp == dtFloat)
    {
        if (value->fValue == 0.0)
            ret = _T("0.0");
        else if (value->fValue < 0.00001 || value->fValue > 100000.0)
        {   // too small or too large, use "nnExx" format
            ret = TCharArray::format(_T("%.8e"),value->fValue);
        }
        else
        {
            ret = TCharArray::format(_T("%.8f"),value->fValue);
            int iDotFrom = ret.find(_T('.'));
            if (iDotFrom >= 0)
            {
                while (ret[-1] == _T('0')) ret.remove(-1);
                if (ret.len() == iDotFrom + 1) ret += _T('0');
            }
        }
    }

    else if (tp == dtWeak)
        ret = TCharArray::format(_T("<weak:0x%X>"),value->vValue);

    else if (tp == dtStrong)
        ret = TCharArray::format(_T("<strong:0x%X>"),value->vValue);

    else throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("type error in Cse_str()"));
}

void Cse_StrEx(CseObj sOut, CseObj value)
{
    TCharArray s;
    Cse_str(s,value);

    TCharArray& sOut_ = (TCharArray&) sOut->sValue;
    sOut_.exchange(s);
}

void Cse_BeStr(TCharArray& ret, CseObj obj)
{
    int tp = CSE_TYPE(obj);
    if (dtId == tp || dtStr == tp)
    {
        ret = *(TCharArray *) &obj->sValue;  // copy string
    }
    else Cse_str(ret,obj);
}

// Following define CSE data access functions
//==============================================================================
CseObj CseInt_new(TInt initVal, TInt flag)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtInt;
    pRes->context.iValue = initVal;
    pRes->context.iFlag  = flag;

    gCseObjectRefs[dtInt]++;
    return (CseObj) &pRes->context;
}

CseObj CseWint_new(TWint initVal)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtWint;
    pRes->context.wValue = initVal;

    gCseObjectRefs[dtWint]++;
    return (CseObj) &pRes->context;
}

CseObj CseFloat_new(TDouble initVal)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtFloat;
    pRes->context.fValue = initVal;

    gCseObjectRefs[dtFloat]++;
    return (CseObj) &pRes->context;
}

CseObj CseStr_new(const TXchar *sValue, int iLen)
{
    TCharArray newStr(sValue,iLen);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStr;
    pRes->context.sValue = __EmptyString;
    pRes->context.iFix  = 0;  // means dynamic size

    TCharArray& sValue_ = (TCharArray&) pRes->context.sValue;
    sValue_.exchange(newStr);

    gCseObjectRefs[dtStr]++;
    return (CseObj) &pRes->context;
}

CseObj CseStr_new(const TCharArray& sValue)
{
    TCharArray newStr(sValue);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStr;
    pRes->context.sValue = __EmptyString;
    pRes->context.iFix = 0;  // means dynamic size

    TCharArray& sValue_ = (TCharArray&) pRes->context.sValue;
    sValue_.exchange(newStr);

    gCseObjectRefs[dtStr]++;
    return (CseObj) &pRes->context;
}

CseObj CseStr_NewEx(TCharArray& sValue)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStr;
    pRes->context.sValue = __EmptyString;
    pRes->context.iFix = 0;  // means dynamic size

    TCharArray& sValue_ = (TCharArray&) pRes->context.sValue;
    sValue_.exchange(sValue);

    gCseObjectRefs[dtStr]++;
    return (CseObj) &pRes->context;
}

STATIC TCseException LogIndexOutRangeErr(int tp = dtNull)
{
    TCharArray sDesc = _T("index out of range");
    if (tp == dtNull)
        return LOG_CSE_ERR(CSE_RANGE_ERR,sDesc);
    else
    {
        if (tp > dtNotator) tp = dtNotator;
        return LOG_CSE_ERR(CSE_RANGE_ERR,Cse_GetTypeName(tp) + _T(' ') + sDesc);
    }
}

TXchar CseStr_append(CseObj str, TXchar ch, int *pIndex)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);
    TCharArray *s = (TCharArray *)&str->sValue;
    s->add(ch,pIndex);
    return ch;
}

TXchar CseStr_get(CseObj str, int index)
{
    TCharArray *s = (TCharArray *)&str->sValue;
    return (*s)[index];
}

void CseStr_set(CseObj str, int index, TXchar ch)
{
    TCharArray *s = (TCharArray *)&str->sValue;
    (*s)[index] = ch;
}

void CseStr_insert(CseObj str, int index, TXchar ch)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *s = (TCharArray *)&str->sValue;
    s->insert(index,ch);
}

CseObj CseStr_slice(CseObj str, int index, int count)
{
    TCharArray *s = (TCharArray *)&str->sValue;
    TCharArray s2 = s->slice(index,count);
    return CseStr_NewEx(s2);
}

void CseStr_remove(CseObj str, int index, int count)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *s = (TCharArray *)&str->sValue;
    s->remove(index,count);
}

void CseStr_clear(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *s = (TCharArray *)&str->sValue;
    s->clear();  // free old buffer
}

void CseStr_assign(CseObj TargStr, const TCharArray& SourStr)
{
    if (TargStr->iFix != 0)
    {   // fix size string
        if ((int) CSE_ARRAY_LEN(TargStr->sValue) != SourStr.len())
            throw LogIndexOutRangeErr(dtStr);
    }

    TCharArray *sTarg = (TCharArray *)&TargStr->sValue;
    *sTarg = SourStr;
}

void CseStr_assign(CseObj TargStr, CseObj SourStr)
{
    ASSERT_TRUE(SourStr != NULL);
    TCharArray *sSour = (TCharArray *)&SourStr->sValue;
    CseStr_assign(TargStr,*sSour);
}

void CseStr_join(CseObj TargStr, const TCharArray& SourStr, int index)
{
    if (TargStr->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *)&TargStr->sValue;
    sTarg->join(SourStr,index);
}

void CseStr_join(CseObj TargStr, CseObj SourStr, int index)
{
    ASSERT_TRUE(SourStr != NULL);
    if (TargStr->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);
        
    TCharArray *sSour = (TCharArray *)&SourStr->sValue;
    TCharArray *sTarg = (TCharArray *)&TargStr->sValue;
    sTarg->join(*sSour,index);
}

int CseStr_SortAdd(CseObj str, TXchar ch)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *)&str->sValue;
    return sTarg->sortAdd(ch);
}

void CseStr_sort(CseObj str)
{
    TCharArray *sTarg = (TCharArray *)&str->sValue;
    sTarg->sort();
}

void CseStr_upper(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->upper();
}

void CseStr_lower(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->lower();
}

void CseStr_trim(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->trim();
}

void CseStr_TrimLeft(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->trimLeft();
}

void CseStr_TrimRight(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->trimRight();
}

int CseStr_truncate(CseObj str, int iLen)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    // truncate not realloc buffer, but clear do
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->truncate(iLen);
}

TUint32 CseStr_hash(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->hash();
}

int CseStr_find(CseObj str, TXchar ch, TBool fromEnd)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->find(ch,fromEnd);
}

int CseStr_find(CseObj str, const TXchar *sSub, int from)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->find(sSub,from);
}

CseObj CseStr_ToInt(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    TInt i;
    if (sTarg->toInt(i))
        return CseInt_new(i);
    else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("translate string to int error"));
}

CseObj CseStr_ToWint(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    TInt64 i;
    if (sTarg->toWint(i))
        return CseWint_new(i);
    else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("translate string to wint error"));
}

CseObj CseStr_ToDouble(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    TDouble f;
    if (sTarg->toDouble(f))
        return CseFloat_new(f);
    else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("translate string to float error"));
}

CseObj CseTier_new(int iSize)
{
    TIntArray newTier(iSize);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtTier;
    pRes->context.tValue = __EmptyTier;
    pRes->context.iFix = 0;  // means dynamic size

    TIntArray& tValue_ = (TIntArray&)pRes->context.tValue;
    tValue_.exchange(newTier);

    gCseObjectRefs[dtTier]++;
    return (CseObj) &pRes->context;
}

CseObj CseTier_new(const TIntArray& tValue)
{
    TIntArray newTier(tValue);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtTier;
    pRes->context.tValue = __EmptyTier;
    pRes->context.iFix = 0;  // means dynamic size

    TIntArray& tValue_ = (TIntArray&)pRes->context.tValue;
    tValue_.exchange(newTier);

    gCseObjectRefs[dtTier]++;
    return (CseObj) &pRes->context;
}

CseObj CseTier_NewEx(TIntArray& tValue)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtTier;
    pRes->context.tValue = __EmptyTier;
    pRes->context.iFix = 0;  // means dynamic size

    TIntArray& tValue_ = (TIntArray&)pRes->context.tValue;
    tValue_.exchange(tValue);

    gCseObjectRefs[dtTier]++;
    return (CseObj) &pRes->context;
}

TInt CseTier_append(CseObj tier, TInt value, int *pIndex)
{
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *t = (TIntArray *)&tier->tValue;
    t->add(value,pIndex);
    return value;
}

TInt CseTier_get(CseObj tier, int index)
{
    TIntArray *t = (TIntArray *)&tier->tValue;
    return (*t)[index];
}

void CseTier_set(CseObj tier, int index, TInt value)
{
    TIntArray *t = (TIntArray *)&tier->tValue;
    (*t)[index] = value;
}

void CseTier_insert(CseObj tier, int index, TInt value)
{
    TIntArray *t = (TIntArray *) &tier->tValue;
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);
    t->insert(index,value);
}

CseObj CseTier_slice(CseObj tier, int index, int count)
{
    TIntArray *t = (TIntArray *) &tier->tValue;
    TIntArray t2 = t->slice(index,count);
    return CseTier_NewEx(t2);
}

void CseTier_remove(CseObj tier, int index, int count)
{
    TIntArray *t = (TIntArray *)&tier->tValue;
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);
    t->remove(index,count);
}

void CseTier_clear(CseObj tier)
{
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *t = (TIntArray *)&tier->tValue;
    t->clear();
}

void CseTier_assign(CseObj TargTier, const TIntArray& SourTier)
{
    if (TargTier->iFix != 0)
    {   // fix size tier
        if ((int) CSE_ARRAY_LEN(TargTier->tValue) != SourTier.len())
            throw LogIndexOutRangeErr(dtTier);
    }

    TIntArray *tTarg = (TIntArray *)&TargTier->tValue;
    *tTarg = SourTier;
}

void CseTier_assign(CseObj TargTier, CseObj SourTier)
{
    ASSERT_TRUE(SourTier != NULL);
    TIntArray *tSour = (TIntArray *)&SourTier->tValue;
    CseTier_assign(TargTier,*tSour);
}

void CseTier_join(CseObj TargTier, const TIntArray& SourTier, int index)
{
    if (TargTier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *tTarg = (TIntArray *)&TargTier->tValue;
    tTarg->join(SourTier,index);
}

void CseTier_join(CseObj TargTier, CseObj SourTier, int index)
{
    ASSERT_TRUE(SourTier != NULL);
    if (TargTier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *tSour = (TIntArray *)&SourTier->tValue;
    TIntArray *tTarg = (TIntArray *)&TargTier->tValue;
    tTarg->join(*tSour,index);
}

int CseTier_SortAdd(CseObj tier, TInt value)
{
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *tTarg = (TIntArray *)&tier->tValue;
    return tTarg->sortAdd(value);
}

void CseTier_sort(CseObj tier)
{
    TIntArray *tTarg = (TIntArray *)&tier->tValue;
    tTarg->sort();
}

int CseTier_truncate(CseObj tier, int iLen)
{
    TIntArray *tTarg = (TIntArray *)&tier->tValue;
    return tTarg->truncate(iLen);
}

CseObj CseBuff_new(int iSize)
{
    TObjArray newBuff(iSize);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtBuff;
    pRes->context.bValue = __EmptyBuff;
    pRes->context.iFix  = 0;  // means dynamic size

    TObjArray& bValue_ = (TObjArray&) pRes->context.bValue;
    bValue_.exchange(newBuff);

    gCseObjectRefs[dtBuff]++;
    return (CseObj) &pRes->context;
}

CseObj CseBuff_new(const TObjArray& bValue)
{
    TObjArray newBuff(bValue);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtBuff;
    pRes->context.bValue = __EmptyBuff;
    pRes->context.iFix  = 0;  // means dynamic size

    TObjArray& bValue_ = (TObjArray&) pRes->context.bValue;
    bValue_.exchange(newBuff);

    gCseObjectRefs[dtBuff]++;
    return (CseObj) &pRes->context;
}

CseObj CseBuff_NewEx(TObjArray& bValue)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtBuff;
    pRes->context.bValue = __EmptyBuff;
    pRes->context.iFix  = 0;  // means dynamic size

    TObjArray& bValue_ = (TObjArray&) pRes->context.bValue;
    bValue_.exchange(bValue);

    gCseObjectRefs[dtBuff]++;
    return (CseObj) &pRes->context;
}

CseObj CseBuff_StolenAppend(CseObj buff, CseObj obj)
{
    ASSERT_TRUE(obj != NULL);
    if (buff->iFix != 0)
    {
        Cse_DecRef(obj);
        throw LogIndexOutRangeErr(dtBuff);
    }
    
    TObjArray *b = (TObjArray *) &buff->bValue;
    b->append(obj);
    Cse_DecRef(obj);
    return obj;
}

CseObj CseBuff_append(CseObj buff, CseObj obj, int *pIndex)
{
    ASSERT_TRUE(obj != NULL);
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);
        
    TObjArray *b = (TObjArray *) &buff->bValue;
    b->add(obj,pIndex);
    return obj;
}

CseObj CseBuff_get(CseObj buff, int index)
{
    TObjArray *b = (TObjArray *) &buff->bValue;
    return b->sub(index);
}

void CseBuff_set(CseObj buff, int index, CseObj value)
{
    ASSERT_TRUE(value != NULL);
    TObjArray *b = (TObjArray *) &buff->bValue;
    b->sub(index) = value;
}

void CseBuff_insert(CseObj buff, int index, CseObj value)
{
    ASSERT_TRUE(value != NULL);
    TObjArray *b = (TObjArray *) &buff->bValue;

    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);
    b->insert(index,value);
}

CseObj CseBuff_slice(CseObj buff, int index, int count)
{
    TObjArray *b = (TObjArray *) &buff->bValue;
    TObjArray b2 = b->slice(index,count);
    return CseBuff_NewEx(b2);
}

void CseBuff_remove(CseObj buff, int index, int count)
{
    TObjArray *b = (TObjArray *) &buff->bValue;
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);
    b->remove(index,count);
}

void CseBuff_clear(CseObj buff)
{
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *b = (TObjArray *)&buff->bValue;
    b->clear();
}

void CseBuff_assign(CseObj TargBuff, const TObjArray& SourBuff)
{
    if (TargBuff->iFix != 0)
    {   // fix size buff
        if ((int) CSE_ARRAY_LEN(TargBuff->bValue) != SourBuff.len())
            throw LogIndexOutRangeErr(dtBuff);
    }

    TObjArray *bTarg = (TObjArray *)&TargBuff->bValue;
    *bTarg = SourBuff;
}

void CseBuff_assign(CseObj TargBuff, CseObj SourBuff)
{
    ASSERT_TRUE(SourBuff != NULL);
    TObjArray *bSour = (TObjArray *)&SourBuff->bValue;
    CseBuff_assign(TargBuff,*bSour);
}

void CseBuff_join(CseObj TargBuff, const TObjArray& SourBuff, int index)
{
    if (TargBuff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *bTarg = (TObjArray *)&TargBuff->bValue;
    bTarg->join(SourBuff,index);
}

void CseBuff_join(CseObj TargBuff, CseObj SourBuff, int index)
{
    ASSERT_TRUE(SourBuff != NULL);
    if (TargBuff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *bSour = (TObjArray *)&SourBuff->bValue;
    TObjArray *bTarg = (TObjArray *)&TargBuff->bValue;
    bTarg->join(*bSour,index);
}

int CseBuff_SortAdd(CseObj buff, CseObj obj)
{
    ASSERT_TRUE(obj != NULL);
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *bTarg = (TObjArray *)&buff->bValue;
    return bTarg->sortAdd(obj);
}

void CseBuff_sort(CseObj buff)
{
    TObjArray *bTarg = (TObjArray *)&buff->bValue;
    bTarg->sort();
}

int CseBuff_truncate(CseObj buff, int iLen)
{
    TObjArray *bTarg = (TObjArray *)&buff->bValue;
    return bTarg->truncate(iLen);
}

CseObj CseBuff_ToNotator(CseObj buff, int index)
{
    ASSERT_TRUE(index >= 0);
    CseObj ret = CseBuff_new(0);
    
    TObjArray *pTarg = (TObjArray *) &ret->bValue;
    TObjArray *pSour = (TObjArray *) &buff->bValue;
    pTarg->join(*pSour,index);
    
    if (pTarg->len() <= 0)
    {
        Cse_DecRef(ret);
        throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("can not convert empty buff to notator"));
    }

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)ret - CSEOBJ_INNER_OFFSET);
    int tp = Cse_type(pTarg->sub(0));
    if (tp >= dtNotator)
        pBase->DataType = dtNotator + dtNull;
    else pBase->DataType = dtNotator + tp;

    gCseObjectRefs[dtBuff]--;
    gCseObjectRefs[dtNotator]++;
    return ret;
}

CseObj CseDict_new(int size)
{
    TEntryArray newDict(size);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtDict;
    pRes->context.entry = NULL;
    pRes->context.iFix = 0; // means dynamic size

    TEntryArray& dValue_ = (TEntryArray&) pRes->context.entry;
    dValue_.exchange(newDict);

    gCseObjectRefs[dtDict]++;
    return (CseObj) &pRes->context;
}

CseObj CseDict_new(const TEntryArray& entry)
{
    TEntryArray newDict(entry);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtDict;
    pRes->context.entry = NULL;
    pRes->context.iFix = 0; // means dynamic size

    TEntryArray& dValue_ = (TEntryArray&) pRes->context.entry;
    dValue_.exchange(newDict);

    gCseObjectRefs[dtDict]++;
    return (CseObj) &pRes->context;
}

CseObj CseDict_NewEx(TEntryArray& entry)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtDict;
    pRes->context.entry = NULL;
    pRes->context.iFix = 0; // means dynamic size

    TEntryArray& dValue_ = (TEntryArray&) pRes->context.entry;
    dValue_.exchange(entry);

    gCseObjectRefs[dtDict]++;
    return (CseObj) &pRes->context;
}

CseObj CseDict_EntryValue(CseObj dict, CseObj key)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->get(key);
}

PEntryPoint CseDict_IdEntry(CseObj dict, const TCharArray& sId, TUint32 hash)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->idEntry(sId,hash);
}

CseObj CseDict_IdEntryValue(CseObj dict, const TCharArray& sId, TUint32 hash)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->getById(sId,hash);
}

CseObj CseDict_StolenSet_(CseObj dict, CseObj key, CseObj value)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;

    if (value == dummy)              // set dummy
        pArray->set(key,CseNull);
    else if (value == NULL)          // remove it
        pArray->set(key,dummy);
    else pArray->set(key,value);
    Cse_DecRef(value);
    
    if (dict->iFix != 0 && pArray->len() > dict->iFix)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("dict exceed fix size"));
    return value;
}

CseObj CseDict_StolenSet(CseObj dict, CseObj key, CseObj value)
{
    if (key == dummy)
        throw LOG_CSE_ERR(CSE_KEY_ERR,_T("dummy is invalid dict key"));
    return CseDict_StolenSet_(dict,key,value);
}

void CseDict_set(CseObj dict, CseObj key, CseObj value)
{
    if (key == dummy)
        throw LOG_CSE_ERR(CSE_KEY_ERR,_T("dummy is invalid dict key"));
    CseDict_StolenSet_(dict,key,Cse_IncRefEx(value));
}

CseObj CseDict_SetEx(CseObj dict, CseObj key, CseObj value)
{
    if (key == dummy)
        throw LOG_CSE_ERR(CSE_KEY_ERR,_T("dummy is invalid dict key"));

    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    TCseObj ret;
    
    if (value == dummy)
        ret = pArray->setEx(key,CseNull);
    else if (value == NULL)
        ret = pArray->setEx(key,dummy);
    else ret = pArray->setEx(key,value);

    if (dict->iFix != 0 && pArray->len() > dict->iFix)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("dict exceed fix size"));
    return Cse_IncRefEx(ret);
}

void CseDict_clear(CseObj dict)
{   // fix size dict also can clear (just clean context)
    // dynamic size dict will realloc buffer
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    pArray->clear();
}

void CseDict_assign(CseObj TargDict, const TEntryArray& SourDict)
{
    if (TargDict->iFix != 0)  // fix size dict
        throw LogIndexOutRangeErr(dtDict);

    TEntryArray *dTarg = (TEntryArray *)&TargDict->entry;
    *dTarg = SourDict;
}

void CseDict_assign(CseObj TargDict, CseObj SourDict)
{
    ASSERT_TRUE(SourDict != NULL);
    TEntryArray *dSour = (TEntryArray *)&SourDict->entry;
    CseDict_assign(TargDict,*dSour);
}

void CseDict_join(CseObj TargDict, const TEntryArray& SourDict)
{
    TEntryArray *dTarg = (TEntryArray *) &TargDict->entry;
    dTarg->join(SourDict);

    if (TargDict->iFix != 0 && dTarg->len() > TargDict->iFix)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("dict exceed fix size"));
}

void CseDict_join(CseObj TargDict, CseObj SourDict)
{
    ASSERT_TRUE(SourDict != NULL);
    TEntryArray *dSour = (TEntryArray *) &SourDict->entry;
    CseDict_join(TargDict,*dSour);
}

CseObj CseDict_StolenBind(CseObj dict, CseObj value)
{
    ASSERT_TRUE(value != NULL);
    
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    pArray->bind(value);
    Cse_DecRef(value);
    return value;
}

void CseDict_bind(CseObj dict, CseObj value)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    pArray->bind(value);
}

CseObj CseDict_GetBinding(CseObj dict)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    return pArray->getBinding();
}

TBool CseDict_enumItem(CseObj dict, PEntryPoint& pEntry)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    return pArray->enumItem(pEntry);
}

CseObj CseNotator_new(CseObj NotatorId)
{
    ASSERT_TRUE(NotatorId != NULL);
    TObjArray newBuff(1);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    
    int tp = CSE_TYPE(NotatorId);
    if (tp >= dtNotator)
        pRes->DataType = dtNotator + dtNull;
    else pRes->DataType = dtNotator + tp;
    
    pRes->context.bValue = __EmptyBuff;
    pRes->context.iFix = 0;  // means dynamic size

    TObjArray& bValue_ = (TObjArray&) pRes->context.bValue;
    bValue_.exchange(newBuff);
    bValue_.sub(0) = NotatorId;

    gCseObjectRefs[dtNotator]++;
    return (CseObj) &pRes->context;
}

CseObj CseStrong_new(CseObj initVal, TInt flag)
{
    ASSERT_TRUE(initVal != NULL);
    
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStrong;
    pRes->context.vValue = Cse_IncRefEx(initVal);
    pRes->context.iFlag  = flag;

    gCseObjectRefs[dtStrong]++;
    return (CseObj) &pRes->context;
}

CseObj CseStrong_StolenSet(CseObj strong, CseObj value)
{
    ASSERT_TRUE(value != NULL);

    CseObj v = strong->vValue;
    strong->vValue = value;
    Cse_DecRef(v);
    return value;
}

void CseStrong_set(CseObj strong, CseObj value)
{
    ASSERT_TRUE(value != NULL);

    CseObj v = strong->vValue;
    strong->vValue = Cse_IncRefEx(value);
    Cse_DecRef(v);
}

STATIC CseObj CseId_new_(const TCharArray& initVal, TUint32 hash)
{
    TCharArray newArray(initVal);

    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtId;
    pRes->context.sValue = __EmptyString;
    pRes->context.hash = hash;

    TCharArray& sValue_ = (TCharArray&) pRes->context.sValue;
    sValue_.exchange(newArray);

    gCseObjectRefs[dtId]++;
    return (CseObj) &pRes->context;
}

STATIC CseObj CseId_NewEx_(TCharArray& initVal, TUint32 hash)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtId;
    pRes->context.sValue = __EmptyString;
    pRes->context.hash = hash;

    TCharArray& sValue_ = (TCharArray&) pRes->context.sValue;
    sValue_.exchange(initVal);

    gCseObjectRefs[dtId]++;
    return (CseObj) &pRes->context;
}

CseObj CseId_new(const TCharArray& sValue)
{
    if (sValue.isEmpty())
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("ID can not empty"));

    TUint32 hash = sValue.hash();
    PEntryPoint pEntry = CseDict_IdEntry(gExistIDs,sValue,hash);

    if (NULL != pEntry->value)
        return Cse_IncRefEx(pEntry->key);
    else
    {
        CseObj ret = CseId_new_(sValue,hash);
        CseDict_StolenSet_(gExistIDs,ret,dummy);
        Cse_DecRef(ret);
        return ret;
    }
}

CseObj CseId_NewEx(TCharArray& sValue)
{
    if (sValue.isEmpty())
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("ID can not empty"));

    TUint32 hash = sValue.hash();
    PEntryPoint pEntry = CseDict_IdEntry(gExistIDs,sValue,hash);

    if (NULL != pEntry->value)
        return Cse_IncRefEx(pEntry->key);
    else
    {
        CseObj ret = CseId_NewEx_(sValue,hash);
        CseDict_StolenSet_(gExistIDs,ret,dummy);
        Cse_DecRef(ret);
        return ret;
    }
}

CseObj CseWeak_new(CseObj initVal, TInt flag)
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtWeak;
    pRes->context.vValue = initVal;
    pRes->context.iFlag  = flag;

    gCseObjectRefs[dtWeak]++;
    return (CseObj) &pRes->context;
}

CseObj CseInstance_new()
{
    CSE_BASE_TYPE *pRes = NEW_CSE_BASE_TYPE;
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtInstance;
    pRes->context.bValue = CseEmptyBuff.addr();
    pRes->context.iFix = 0;  // means dynamic size

    gCseObjectRefs[dtInstance]++;
    return (CseObj) &pRes->context;
}

TBool CseFree_DoNothing(CseObj obj)
{
    return true; // do nothing
}

TBool CseFree_DirectReturn(CseObj obj)
{
    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

TBool CseFree_ReturnSBuff(CseObj obj)
{
    TCharArray s;
    TCharArray& sValue_ = (TCharArray&) obj->sValue;
    sValue_.exchange(s);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

class CseObjectCall
{
private:
    CseObj m_data;

public:
    CseObjectCall() { m_data = dummy; }
    CseObjectCall(const CseObjectCall& obj) { m_data = obj.m_data; }
};

TBool CseFree_ReturnTValue(CseObj obj)
{
    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);

    TIntArray t;
    TIntArray& tValue_ = (TIntArray&)obj->tValue;
    tValue_.exchange(t);

    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

TBool CseFree_ReturnBValue(CseObj obj)
{
    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);

    if (Cse_OptionOn(obj,18) && Cse_len(obj) >= 1)
    {   // run __exit__() function
        pBase->RefCount++;  // avoid increase zero refcount, and avoid meet zero again when decreasing
        CseObj vOnExit = obj->bValue[0];

        int tp = CSE_TYPE(vOnExit);
        if (tp == dtInt && vOnExit->vValue != NULL)
        {
            union {
                void (CseObjectCall::* ThisCall)();
                void *FuncAddr;
            } AUnion;
            AUnion.FuncAddr = (void*) vOnExit->vValue;

            void (CseObjectCall::* ExitFunc)() = AUnion.ThisCall;
            (((CseObjectCall *)&obj)->*ExitFunc)();
        }
        else if (tp == CSE_ATOMCALL_FLAG && gScriptEvalFunc != NULL && gScriptEvalFunc->iValue != 0)
        {
            TCseObj (*_EvalNode)(const TCseObj& cmd, const TCseObj& space) = (TCseObj (*)(const TCseObj&,const TCseObj&)) gScriptEvalFunc->iValue;
            TCseObj cmd = TCseObj::format(CSE_NOTATOR,vOnExit);
            cmd.append(obj);

            _EvalNode(cmd,CseBltinModule);
        }
    }

    TObjArray b;
    TObjArray& bValue_ = (TObjArray&) obj->bValue;
    bValue_.exchange(b);

    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

TBool CseFree_ReturnDict(CseObj obj)
{
    TEntryArray d;
    TEntryArray& dValue_ = (TEntryArray&) obj->entry;
    dValue_.exchange(d);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

TBool CseFree_ReturnInstance(CseObj obj)
{
    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    pBase->RefCount++;  // protect CseInstance_free call

    try
    {
        CseInstance_free(obj);
    }
    catch(...)
    {
        pBase->RefCount--;
        throw;
    }
    pBase->RefCount--;

    if (0 == pBase->RefCount)
    {
        TObjArray b;
        TObjArray& bValue_ = (TObjArray&) obj->bValue;
        bValue_.exchange(b);

        DEL_CSE_BASE_TYPE(pBase);
        return true;
    }
    else return false;
}

TBool CseFree_ReturnId(CseObj obj)
{
    Cse_SpecialFree(gExistIDs->entry,obj,obj->hash);

    TCharArray s;
    TCharArray& value_ = (TCharArray&)obj->sValue;
    value_.exchange(s);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

TBool CseFree_ReturnStrong(CseObj obj)
{
    CseObj v = obj->vValue;
    obj->vValue = dummy;
    Cse_DecRef(v);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    DEL_CSE_BASE_TYPE(pBase);
    return true;
}

// only called when exit
void Cse_free(CseObj value, TBool recursive)
{
    int tp = CSE_TYPE(value);

    if (tp == dtBuff || tp >= dtNotator)
    {
        if (recursive)
        {
            if (! Cse_OptionOn(value,CSEOBJ_FREE_FLAG))
            {
                Cse_SetOption(value,CSEOBJ_FREE_FLAG);
                int iLen = CSE_ARRAY_LEN(value->bValue);
                for (int iCount = 0; iCount < iLen; iCount++)
                {
                    CseObj v = value->bValue[iCount];
                    value->bValue[iCount] = dummy;
                    Cse_free(v,true);
                }
                Cse_ClearOption(value,CSEOBJ_FREE_FLAG);
            }
        }
        else CseBuff_clear(value);
    }

    else if (tp == dtDict)
    {
        if (recursive)
        {
            if ( ! Cse_OptionOn(value,CSEOBJ_FREE_FLAG) )
            {
                Cse_SetOption(value,CSEOBJ_FREE_FLAG);

                CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)value->entry - sizeof(CSE_DICT_EXT));
                TEntryArray *pArray = (TEntryArray *) &value->entry;
                PEntryPoint pEntry = NULL;
                while (pArray->enumItem(pEntry))
                {
                    CseObj v = pEntry->value;
                    CseObj v2 = pEntry->key;
                    pEntry->key = dummy;
                    pEntry->value = NULL;
                    pDictExt->count--;
                    Cse_free(v,true);
                    Cse_free(v2,true);
                }

                CseObj v = Cse_IncRefEx(pArray->getBinding());
                if (v != dummy)
                {   // in most case, dict binding is dummy
                    pArray->bind(dummy);
                    Cse_free(v,true);
                }

                Cse_ClearOption(value,CSEOBJ_FREE_FLAG);
            }
        }
        else CseDict_clear(value);
    }

    else if (tp == dtStrong)
    {
        CseObj v = value->vValue;
        value->vValue = dummy;
        if (recursive)
          Cse_free(v,true);
        else Cse_DecRef(v);
    }

    Cse_DecRef(value);
}

// Following define register table API
//==============================================================================
STATIC TBool AdjustSegment(const TCharArray& key, TCharArray& seg)
{
    seg = key;
    int iLen = seg.len();
    if (iLen <= 0) return false;

    for (int i = 0; i < iLen; i++)
    {
        TXchar ch = seg[i];
        TXchar offset = _T('a') - _T('A');
        if (ch >= _T('a') && ch <= _T('z'))  // uppercase
            seg[i] = ch - offset;
        else if (_T('\\') == ch)             // chang "\" to "/"
            seg[i] = _T('/');
    }

    if (_T('/') == seg[iLen-1])              // remove last "/"
    {
        seg.truncate(iLen-1);
        return iLen > 1;
    }
    return true;
}

CseObj CseRegist_get(const TCharArray& key)
{
    TCharArray seg;
    if (! AdjustSegment(key,seg))
        return NULL;
    return CseDict_IdEntryValue(gCseRegistTable,seg,seg.hash());
}

TBool CseRegist_exist(const TCharArray& key)
{
    return NULL != CseRegist_get(key);
}

CseObj CseRegist_StolenSet(const TCharArray& key, CseObj value)
{
    TCharArray seg;
    if (! AdjustSegment(key,seg))
    {
        Cse_DecRef(value);
        return dummy;
    }

    CseObj id = CseId_new(seg);
    CseDict_StolenSet(gCseRegistTable,id,value);
    Cse_DecRef(id);

    return value;
}

CseObj CseRegist_set(const TCharArray& key, CseObj value)
{
    return CseRegist_StolenSet(key,Cse_IncRefEx(value));
}

void CseRegist_delete(const TCharArray& key)
{
    TCharArray seg;
    if (! AdjustSegment(key,seg)) return;

    CseObj id = CseId_new(seg);
    CseDict_StolenSet(gCseRegistTable,id,NULL);
    Cse_DecRef(id);
}

CseObj CseRegist_StolenHold(CseObj value)
{
    int tp = CSE_TYPE(value);
    if (dtInstance == tp)
    {   // holding object is automatic free, instance should free by manual before system exit
        Cse_DecRef(value);
        throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("register can not hold instance"));
    }
    return CseBuff_StolenAppend(gCsePreserves,value);
}

void CseRegist_hold(CseObj value)
{
    CseRegist_StolenHold(Cse_IncRefEx(value));
}

// Following define module init and exit
//==============================================================================
void BaseTypes_init(void)
{
#ifndef CLOSE_REF_CHECK
    extern TInt32 gTotalCharArrayCount;
    gGlobalCharArrayCount = gTotalCharArrayCount;
#endif

    gExistIDs = CseDict_new();

    for (int i = 0; i <= dtNotator; i++)
        gFreeObjProc[i] = CseFree_DoNothing;

    gFreeObjProc[dtInt]      = CseFree_DirectReturn;
    gFreeObjProc[dtWint]     = CseFree_DirectReturn;
    gFreeObjProc[dtFloat]    = CseFree_DirectReturn;
    gFreeObjProc[dtStr]      = CseFree_ReturnSBuff;
    gFreeObjProc[dtTier]     = CseFree_ReturnTValue;
    gFreeObjProc[dtBuff]     = CseFree_ReturnBValue;
    gFreeObjProc[dtDict]     = CseFree_ReturnDict;
    gFreeObjProc[dtInstance] = CseFree_ReturnInstance;
    gFreeObjProc[dtId]       = CseFree_ReturnId;
    gFreeObjProc[dtStrong]   = CseFree_ReturnStrong;
    gFreeObjProc[dtWeak]     = CseFree_DirectReturn;
    gFreeObjProc[dtNotator]  = CseFree_ReturnBValue;

    gCseRegistTable   = CseDict_new();
    gCsePreserves      = CseBuff_new(0);

    CseNull = CseBuff_StolenAppend(gCsePreserves,CseInstance_new());
    
    gCseDisableLnDbg   = CseRegist_StolenSet(_T("KERNEL/DISABLE_LN_DBG"),CseInt_new(0));
    gCseTypeStrFunc    = CseRegist_StolenSet(_T("KERNEL/TYPE_STR_FUNC"),CseInt_new(0));
    gCseInstFreeFunc   = CseRegist_StolenSet(_T("KERNEL/FREE_FUNC"),CseInt_new(0));
    gCseInstCmpFunc    = CseRegist_StolenSet(_T("KERNEL/CMP_FUNC"),CseInt_new(0));
    gCseInstEqualFunc  = CseRegist_StolenSet(_T("KERNEL/EQU_FUNC"),CseInt_new(0));
    gCseInstStrFunc    = CseRegist_StolenSet(_T("KERNEL/STR_FUNC"),CseInt_new(0));
    gCseInstBeStrFunc  = CseRegist_StolenSet(_T("KERNEL/BESTR_FUNC"),CseInt_new(0));
    gCseInstAsKeyFunc  = CseRegist_StolenSet(_T("KERNEL/ASKEY_FUNC"),CseInt_new(0));
    gCseInstMapVarFunc = CseRegist_StolenSet(_T("KERNEL/MAPVAR_FUNC"),CseInt_new(0));
    gCseLogErrorStack  = CseRegist_StolenSet(_T("KERNEL/LOGERR_FUNC"),CseInt_new(0));

    CseEmptySpace   = CseDict_new(8);
    CseThreadStacks = CseDict_new(8);
    CseTraceStack   = CseBuff_new(0);

    gAssertIsReady = true;
}

STATIC void CleanRegistTable()
{
    Cse_IncRef(gCseRegistTable);
    Cse_free(gCseRegistTable,true);
    Cse_IncRef(gCsePreserves);
    Cse_free(gCsePreserves,true);
}

void BaseTypes_exit(void)
{
    gAssertIsReady = false;

    // clean context of regist table
    if (gCheckRefCount)
        CleanRegistTable();
    else
    {
        try
        {
            CleanRegistTable();
        }
        catch(...) {}
    }

    // free space system, regist table, ID-name buffer
    try
    {   // free space system
        Cse_free(CseMainModule,true);
        Cse_free(CseBltinModule,true);
        Cse_free(CseEmptySpace,true);
        Cse_free(CseThreadStacks,true);

        // free regist table
        Cse_DecRef(gCseRegistTable);
        Cse_DecRef(gCsePreserves);

        // free trace stack
        CseBuff_clear(CseTraceStack);
        Cse_DecRef(CseTraceStack);

        // free ID-name buffer
        Cse_DecRef(gExistIDs);
    }
    catch(...) {}
    
    // wholely exit CSE kernel and try check reference count
    TXchar MsgBuff[1024] = {'\0'};
    if (gCheckRefCount)
    {
        TCharArray sErr;
        for (int i = 0; i <= dtNotator; i++)
        {
            if (gCseObjectRefs[i] != 0)
                sErr += TCharArray::format(_T("%s RefCount unbalance:%d\n"),Cse_GetTypeName(i),gCseObjectRefs[i]);
        }

        if (! sErr.isEmpty())
            LOG_MSG(_T("%s"),sErr.addr());

#ifndef CLOSE_REF_CHECK
        {
            extern TInt32 gTotalIntObjCount;
            extern TInt32 gTotalWintObjCount;
            extern TInt32 gTotalFloatObjCount;
            extern TInt32 gTotalCharArrayCount;
            extern TInt32 gTotalIntArrayCount;
            extern TInt32 gTotalObjArrayCount;
            extern TInt32 gTotalEntryArrayCount;
            extern TInt32 gTotalCseObjCount;

            TXchar buff[256];
            SPRINTF(buff,_T("existing TIntObj: %d\n"),gTotalIntObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TWintObj: %d\n"),gTotalWintObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TFloatObj: %d\n"),gTotalFloatObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);

            SPRINTF(buff,_T("existing TCharArray: %d\n"),gTotalCharArrayCount - gGlobalCharArrayCount - 1); // sErr occupy one
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TIntArray: %d\n"),gTotalIntArrayCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TObjArray: %d\n"),gTotalObjArrayCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TEntryArray: %d\n"),gTotalEntryArrayCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TCseObj: %d\n"),gTotalCseObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
        }
#endif
    }
    else SPRINTF(MsgBuff,_T("application exiting"));

    if ( gHitBeforeExit )
    {
#if defined(__VISUALC__) || defined(__MINGW32__)
  #ifdef WINCE
        MessageBox(NULL,MsgBuff,_T("reference count"),MB_OK);
  #else
        MessageBox(NULL,MsgBuff,_T("reference count"),MB_OK | MB_SYSTEMMODAL);
  #endif
#else
        TXchar buff[256];
        SPRINTF(buff,_T("input 'exit' to quit\n"));
        FGETS(buff,256,stdin);
#endif
    }    
}

extern "C" {
  void Cse_CloseRefCheck(void)
  {
    gCheckRefCount = false;
  }

  void Cse_CloseLineDbg(void)
  {
    if (gCseDisableLnDbg != NULL)
        gCseDisableLnDbg->iValue = 1;
  }

  void Cse_HitWhenExit(void)
  {
    gHitBeforeExit = true;
  }

  CseObj Cse_GetRegister(const TXchar *name)
  {   // define C style API for easy accessing dll
    return CseRegist_get(name);
  }
}
